package com.zhkj.lib.http

import com.zhkj.lib.base.BaseApplication
import com.zhkj.lib.base.QueryShippingResponse
import com.zhkj.lib.base.UploadResponse
import com.zhkj.lib.config.BASE_URL
import io.reactivex.Observable
import io.reactivex.ObservableTransformer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import top.zibin.luban.Luban
import java.io.File

abstract class BaseManager<ApiService : BaseApiService>(apiServiceClass: Class<ApiService>) {

    protected val apiService: ApiService =
        HttpServiceFactory.createService(apiServiceClass, BASE_URL)

    /**
     * 在子线程加载数据
     */
    protected fun <Response : BaseResponse> observeOnMain(): ObservableTransformer<Response, Response> {
        return ObservableTransformer { upstream: Observable<Response> ->
            upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
        }
    }

    /**
     * 网络加载数据观察
     */
    protected fun <Response : BaseResponse> subscribe(
        observable: Observable<Response>,
        listener: ResponseSubscribeListener<Response>
    ): Disposable {
        return observable.doOnSubscribe { listener.onStart() }
            .compose(observeOnMain<Response>())
            .subscribe({
                listener.onSuccess(it)
            }, {
                listener.onFailure(it)
            })
    }

    /**
     * 上传单张图片(先压缩，再上传)
     * p.s
     */
    fun uploadPicture(
        imageFilePath: String,
        listener: SubscribeListener<UploadResponse>
    ): Disposable {
        var cachePath: String? = null
        return Observable.just(imageFilePath).map {
            listener.onStart()
            Luban.with(BaseApplication.INSTANCE).load(it).ignoreBy(2 * 1024)
                .setTargetDir(BaseApplication.INSTANCE.cacheDir.path).get()[0]
        }.flatMap {
            val requestBody = it.asRequestBody("multipart/form-data".toMediaType())
            val part = MultipartBody.Part.createFormData("file", imageFilePath, requestBody)
            if (imageFilePath != it.path) cachePath = it.path
            apiService.uploadPicture(part)
        }.observeOn(Schedulers.io()).subscribeOn(Schedulers.io()).subscribe({
            cachePath?.let { File(cachePath!!).delete() }
            when (it.code) {
                1, 10001 -> listener.onSuccess(it.apply {
                    it.data?.filePath = imageFilePath
                })
                else -> listener.onFailure(HttpResponseException(it.code ?: 0, it.msg))
            }
        }, {
            cachePath?.let { File(cachePath!!).delete() }
            listener.onFailure(it)
        })
    }

    /**
     * 上传多张图片(先压缩，再上传)
     * p.s 接口后面刚加上的
     */
    fun uploadPicture(
        fileList: MutableList<String>,
        listener: SubscribeListener<UploadResponse>
    ): Disposable {
        val cacheList = mutableListOf<String>()
        return Observable.just(fileList).map { list ->
            listener.onStart()
            Luban.with(BaseApplication.INSTANCE).load(list).setTargetDir(BaseApplication.INSTANCE.cacheDir.path).get()
        }.flatMap { list ->
            val partList = mutableListOf<MultipartBody.Part>()
            for (file in list) {
                if(!fileList.contains(file.path)) cacheList.add(file.path)
                val requestBody = file.asRequestBody("multipart/form-data".toMediaType())
                val part = MultipartBody.Part.createFormData("file[]", file.name, requestBody)
                partList.add(part)
            }
            apiService.uploadPicture(partList)
        }.observeOn(Schedulers.io()).subscribeOn(Schedulers.io()).subscribe({ response ->
            for (cachePath in cacheList) File(cachePath).delete()
            when (response.code) {
                1, 10001 -> listener.onSuccess(response)
                else -> listener.onFailure(HttpResponseException(response.code ?: 0, response.msg))
            }
        }, {
            for (cachePath in cacheList) File(cachePath).delete()
            listener.onFailure(it)
        })
    }

    /**
     * 查询快递详情
     */
    fun queryShipping(
        token: String, shippingNo: String, shippingCode: String,
        listener: SubscribeListener<QueryShippingResponse>
    ): Disposable {
        val queryShipping = apiService.queryShipping(token, shippingNo, shippingCode)
        return subscribe(queryShipping, ResponseSubscribeListener(listener))
    }
}